#ifndef _ASM_CALL_H
#define _ASM_CALL_H


struct _comboVal 
{
	union
		{
			void *ptr;
			float f;
			unsigned long ue;
			signed long se;
			struct
			{
				union
				{
					signed short sx;
					unsigned short ux;
					struct 
					{
						union 
						{
							signed char sl;
							unsigned char ul;
						};
						union 
						{
							signed char sh;
							unsigned char uh;
						};
					};
				};
				short _;
			};
	};
	_comboVal &operator=(unsigned char v) {ul = v;return *this;}
	_comboVal &operator=(signed char v) {sl = v;return *this;}
	_comboVal &operator=(unsigned short v) {ux = v;return *this;}
	_comboVal &operator=(signed short v) {sx = v;return *this;}
	_comboVal &operator=(unsigned long v) {ue = v;return *this;}
	_comboVal &operator=(signed long v) {se = v;return *this;}
	_comboVal &operator=(unsigned int v) {ue = v;return *this;}
	_comboVal &operator=(signed int v) {se = v;return *this;}
	_comboVal &operator=(float v) {f = v;return *this;}
	bool operator==(unsigned char v) {return ul == v;}
	bool operator==(signed char v) {return sl == v;}
	bool operator==(unsigned short v) {return ux == v;}
	bool operator==(signed short v) {return sx == v;}
	bool operator==(unsigned long v) {return ue == v;}
	bool operator==(signed long v) {return se == v;}
	bool operator==(unsigned int v) {return ue == v;}
	bool operator==(signed int v) {return se == v;}
	bool operator==(float v) {return f == v;}
	template<typename T>  bool operator==(T* v) {return ptr == (void*)v;}
	operator unsigned char() {return ul;}
	operator signed char() {return sl;}
	operator unsigned short() {return ux;}
	operator signed short() {return sx;}
	operator unsigned long () {return ue;}
	operator signed long () {return se;}
	operator unsigned int () {return ue;}
	operator signed int () {return se;}
	operator float() {return f;}
	template<typename T> operator T*() {return (T*)ptr;}
};

typedef _comboVal _regVal,_stackVal;






enum RegisterNames
{
	_EAX = 0,_EBX,_ECX,_EDX,_ESI,_EDI,_EBP,regCount 
};

class AsmCall
{
public:
	AsmCall(AsmCall &other)
		:mAddress(other.mAddress), mRetvalRegister(other.mRetvalRegister),
		mStackSize(other.mStackSize),mPostCall(other.mPostCall) 
	{
		memcpy(mInputRegisters,other.mInputRegisters ,regCount*4); 
		memcpy(mOutputRegisters,other.mOutputRegisters ,regCount*4);
		memcpy(mStack ,other.mStack,80);

	}
	AsmCall(DWORD address,RegisterNames resultReg = _EAX) 
		:mAddress(address),mRetvalRegister(resultReg)
	{
		reset();
	}
	void reset(bool keepStack=false,bool keepRegisters=false)
	{
		if (!keepStack)
		{
			mStackSize = 0;
			for (int i = 0; i < 20 ; i++ ) mStack[i] = (long)0;
		}
		if (!keepRegisters)
			for (int i = 0; i < regCount; i++)
				mInputRegisters[i] = (long)0;
		mPostCall = false;
	}
	template <typename T> void push(T val) {mStack[mStackSize] = val; mStackSize++;}
	_regVal &_register(RegisterNames reg)
	{
		if (mPostCall)
			return mOutputRegisters[reg];
		else
			return mInputRegisters[reg];
	}
	_comboVal &operator()()
	{
		call();
		mPostCall = true;
		return  mOutputRegisters[mRetvalRegister];
	}
private:
	RegisterNames mRetvalRegister;

	_regVal mInputRegisters[regCount];
	_regVal mOutputRegisters[regCount];
	_stackVal mStack[20];
	unsigned long mStackSize;
	DWORD mAddress;
	bool mPostCall;

	void call();

};




#endif //_ASM_CALL_H